package eteam.aps.service.impl;

import cn.hutool.core.bean.BeanUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import eteam.aps.common.component.LoginUserRedisService;
import eteam.aps.common.constant.*;
import eteam.aps.common.entity.ParentEntity;
import eteam.aps.common.helper.Helper;
import eteam.aps.mapper.*;
import eteam.aps.model.entity.BaseEntity;
import eteam.aps.model.entity.ScanProAlready;
import eteam.aps.model.entity.ScanProWithout;
import eteam.aps.model.entity.ScanProcessStep;
import eteam.aps.model.entity.other.ScanCount;
import eteam.aps.model.entity.other.ScanProcess;
import eteam.aps.model.entity.other.ScanReport;
import eteam.aps.model.entity.sale.ProductProcessOl;
import eteam.aps.model.vo.moco_rders.MocoRdersDisplayVo;
import eteam.aps.model.vo.process_materials.ProcessMaterialsVo;
import eteam.aps.model.vo.scan.*;
import eteam.aps.model.vo.working_procedure.WorkingProcedureVo;
import eteam.aps.service.MocoRdersProcessService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 工单工序 业务实现层
 *
 * @author LiuLei
 */
@Service
public class MocoRdersProcessServiceImpl implements MocoRdersProcessService {

    @Autowired
    private MocoRdersMapper mocoRdersMapper;

    @Autowired
    private ProcessMaterialsMapper processMaterialsMapper;

    @Autowired
    private WorkingProcedureMapper workingProcedureMapper;

    @Autowired
    private ProductNumberMapper productNumberMapper;

    @Autowired
    private ProductProcessOlMapper productProcessOlMapper;

    @Autowired
    private SystemMapper systemMapper;

    @Autowired
    private ScanProcessStepMapper scanProcessStepMapper;

    @Autowired
    private ScanProWithoutMapper scanProWithoutMapper;

    @Autowired
    private ScanProAlreadyMapper scanProAlreadyMapper;

    @Autowired
    private LoginUserRedisService loginUserRedisService;

    @Override
    @Transactional
    public ScanProcessShow<?> scanInfo(ScanProcess scanProcess) throws Exception {
        ScanProcessShow<Object> show = new ScanProcessShow<>();
        Map<String, Object> map = new HashMap<>(8);
        // 状态不为删除
        map.put("fState", ParentEntity.FSTATE_DELETED);
        // 当前扫描的数据
        map.put("code", scanProcess.getScan());
        // 状态
        map.put("State", -1);
        // 扫描工单？ 排除已经报工的产品 状态位 草稿和生产中
        map.put("start", ProductType.ERROR);
        map.put("end", ProductType.FINISH);
        MocoRdersDisplayVo moc = mocoRdersMapper.selMocByProBarCode(map);
        // 扫描工序？
        WorkingProcedureVo wp = workingProcedureMapper.selWPSimByName(map);
        // 扫描人员？
        BaseEntity entity = systemMapper.selectEmpName(map);
        if (moc == null && wp == null && entity == null) { //暂无扫描数据
            show.setScanCode(ScanType.ERROR);
            show.setScanMsg("暂无扫描的数据！");
            return show;
        } else {
            String fuserid = loginUserRedisService.getUser().getFuserid();
            if (moc != null) {
                Map<String, Object> draftMap = new HashMap<>(5);
                draftMap.put("modify", fuserid);
                draftMap.put("time", LocalDateTime.now());
                draftMap.put("processing", ProductType.PROCESSING);
                draftMap.put("draft", ProductType.DRAFT);
                draftMap.put("scan", scanProcess.getScan());
                productNumberMapper.updateProTypeByBarCodeWithDraft(draftMap);
                if (Helper.isNotEmpty(scanProcess.getWpCode())
                        && Helper.isNotEmpty(scanProcess.getScan())) {
                    Integer count = productProcessOlMapper.selectCount(new LambdaQueryWrapper<ProductProcessOl>()
                            .eq(ProductProcessOl::getfWorkCode, scanProcess.getWpCode())
                            .eq(ProductProcessOl::getfBarCode, scanProcess.getScan())
                    );
                    if (count > 0) {
                        show.setScanCode(ScanType.ERROR);
                        show.setScanMsg("该产品对应的工序已报工！");
                        return show;
                    }
                    Map<String, Object> query = new HashMap<>(3);
                    query.put("state", ParentEntity.FSTATE_DELETED);
                    query.put("check", CheckType.CHECK);
                    query.put("code", scanProcess.getScan());
                    String preCode = workingProcedureMapper.selectPreWorkByCode(query);
                    if (Helper.isNotEmpty(preCode)) {
                        count = productProcessOlMapper.selectCount(new LambdaQueryWrapper<ProductProcessOl>()
                                .eq(ProductProcessOl::getfWorkCode, preCode)
                                .eq(ProductProcessOl::getfBarCode, scanProcess.getBarCode())
                        );
                        if (count <= 0) {
                            show.setScanCode(ScanType.ERROR);
                            show.setScanMsg("该工序的前置工序" + preCode + "未完成，请先完成前置工序！");
                            return show;
                        }
                    }
                }
                scanProcess.setBarCode(scanProcess.getScan());
                //工单不为空
                // 产品编号不为空(根据产品任务号 去查询对应的物料)  并保存到(未扫描物料表)【1. 未取过，2 取过】
                List<ScanProWithoutVo> withoutVoList = scanProWithoutMapper.selListByBarCode(map);
                if (withoutVoList.isEmpty()) {// 没有 从物料表里查询并保存
//                    map.put("modId", Collections.singletonList(moc.getfMoDId()));
                    map.put("mocCode", moc.getfMocCode());
                    // 查询改产品对应的工序
                    List<ProcessMaterialsVo> mocrLis = processMaterialsMapper.selPMLis(map);
//                    List<MocoRdersBordy> moList = mocoRdersBordyMapper.getByMoList(map);
                    // todo 这里要进行 维护前的提示【已完成】
                    Set<ScanProWithout> list = mocrLis.stream()
                            .filter(data -> Helper.isNotEmpty(data.getfScaPro()))
                            .map(data -> {
                                        ScanProWithout scanProWithout = new ScanProWithout(
                                                scanProcess.getScan(), // 条码
                                                data.getfSortSeq(), // 序号
                                                data.getfInvCode(), // 产品编号
                                                data.getFclnvName(), // 产品名称
                                                data.getFclnvStd(), // 产品规格
                                                new BigDecimal(data.getfQty()), // 需求数
                                                new BigDecimal("0"), // 已扫描数
                                                data.getfScaPro(), // 工序编号
                                                data.getfProName());// 工序名称
                                        Helper.setDefaultAddValue(scanProWithout, fuserid);
                                        return scanProWithout;
                                    }
                            ).collect(Collectors.toSet());
                    // 只要不为空 就批量保存数据
                    if (!list.isEmpty()) {
                        scanProWithoutMapper.batchInsertScanProWithout(list);
                    } else {
                        show.setScanCode(ScanType.ERROR);
                        show.setScanMsg("该产品暂无可维护的工序！");
                        return show;
                    }
                }
                // 记录操作步骤
                ScanProcessStep scanProcessStep = setScanStep(moc, scanProcess, show);
                if (scanProcessStep != null) {
                    Helper.setDefaultAddValue(scanProcessStep, fuserid);
                    scanProcessStepMapper.addScanStep(scanProcessStep);
//                    // 将该产品修改为生产中
//                    Map<String, Object> upt = new HashMap<>(4);
//                    upt.put("processing", ProductType.PROCESSING);
//                    upt.put("scan", scanProcess.getScan());
//                    upt.put("modify", fuserid);
//                    upt.put("time", LocalDateTime.now());
//                    productNumberMapper.updateProTypeByBarCode(upt);
                }
                show.setData(new ScanMoc(scanProcess.getScan(), BeanUtil.copyProperties(moc, MocoRdersDisplayVo.class)));
            }
            // 扫描工序？工序不为空
            if (wp != null) {
                if (Helper.isNotEmpty(scanProcess.getBarCode())
                        && Helper.isNotEmpty(scanProcess.getScan())) {
                    Integer count = productProcessOlMapper.selectCount(new LambdaQueryWrapper<ProductProcessOl>()
                            .eq(ProductProcessOl::getfWorkCode, scanProcess.getScan())
                            .eq(ProductProcessOl::getfBarCode, scanProcess.getBarCode())
                    );
                    if (count > 0) {
                        show.setScanCode(ScanType.ERROR);
                        show.setScanMsg("该产品对应的工序已报工！");
                        return show;
                    }
                    Map<String, Object> query = new HashMap<>(3);
                    query.put("state", ParentEntity.FSTATE_DELETED);
                    query.put("check", CheckType.CHECK);
                    query.put("code", scanProcess.getScan());
                    String preCode = workingProcedureMapper.selectPreWorkByCode(query);
                    if (Helper.isNotEmpty(preCode)) {
                        count = productProcessOlMapper.selectCount(new LambdaQueryWrapper<ProductProcessOl>()
                                .eq(ProductProcessOl::getfWorkCode, preCode)
                                .eq(ProductProcessOl::getfBarCode, scanProcess.getBarCode())
                        );
                        if (count <= 0) {
                            show.setScanCode(ScanType.ERROR);
                            show.setScanMsg("该工序的前置工序" + preCode + "未完成，请先完成前置工序！");
                            return show;
                        }
                    }
                }
                scanProcess.setWpCode(wp.getfCode());
                scanProcess.setWpName(wp.getfName());
                // 记录操作步骤
                ScanProcessStep scanProcessStep = setScanStep(wp, scanProcess, show);
                if (scanProcessStep != null) {
                    Helper.setDefaultAddValue(scanProcessStep, fuserid);
                    scanProcessStepMapper.addScanStep(scanProcessStep);
                }
                show.setData(new ScanInfo(wp.getfCode(), wp.getfName()));
            }
            // 扫描人员？人员不为空
            if (entity != null) {
                scanProcess.setUserCode(entity.getId());
                scanProcess.setUserName(entity.getName());
                // 记录操作步骤
                ScanProcessStep scanProcessStep = setScanStep(entity, scanProcess, show);
                if (scanProcessStep != null) {
                    Helper.setDefaultAddValue(scanProcessStep, fuserid);
                    scanProcessStepMapper.addScanStep(scanProcessStep);
                }
                show.setData(new ScanInfo(entity.getId(), entity.getName()));
            }
        }
        return show;
    }

    @Override
    public ScanInvVo selectInv(ScanProcess scanProcess) {
        Map<String, Object> map = new HashMap<>(4);
        map.put("fState", ParentEntity.FSTATE_DELETED);
        map.put("fBarCode", scanProcess.getBarCode());
        map.put("fWpCode", scanProcess.getWpCode());
        List<ScanProWithoutVo> without = scanProWithoutMapper.selByScanQuery(map);
        map.put("proState", ScanProType.TEARDOWN);
        List<ScanProAlreadyVo> already = scanProAlreadyMapper.selScanProAlready(map);
        return new ScanInvVo(already, without);
    }

    @Override
    @Transactional
    public ScanProcessShow<ScanInvVo> scanInv(ScanProcess scanProcess) throws Exception {
        ScanProcessShow<ScanInvVo> show = new ScanProcessShow<>();
        Map<String, Object> map = new HashMap<>(3);
        // 状态不为删除
        map.put("fState", ParentEntity.FSTATE_DELETED);
        // 当前扫描的数据
        map.put("invBar", scanProcess.getScan());
        int count = scanProAlreadyMapper.selScanProOkCount(map);
        if (count > 0) {
            show.setScanCode(ScanType.ERROR);
            show.setScanMsg("已存在物料条码信息！");
            return show;
        }
        map.clear();
        // 状态不为删除
        map.put("fState", ParentEntity.FSTATE_DELETED);
        // 当前扫描的数据
        map.put("code", scanProcess.getBarCode());
        map.put("fInvCode", scanProcess.getInvCode());
        ScanProWithoutVo scanProWithout = scanProWithoutMapper.selByInvCode(map);
        if (scanProWithout == null) { // 没有找到数据
            show.setScanCode(ScanType.ERROR);
            show.setScanMsg("暂无扫描的物料信息！");
            return show;
        } else {
            Helper.setEmptyWithNull(scanProWithout);
            String fuserid = loginUserRedisService.getUser().getFuserid();
            // 已扫描数加一
            scanProWithout.setfAlreadyQty(scanProWithout.getfAlreadyQty().add(BigDecimal.ONE));
            // 修改 原来的工序
            scanProWithout.setfLastModifyUserId(fuserid);
            scanProWithout.setfLastModifyTime(LocalDateTime.now());
            scanProWithoutMapper.updateQtyScanProWithout(scanProWithout);
            // 新增加已扫描数据
            ScanProAlready scanProAlready = new ScanProAlready(
                    scanProcess.getBarCode(), // 条码
                    scanProcess.getWpCode(), // 工序编码
                    scanProcess.getWpName(), // 工序名称
                    scanProcess.getUserName(), // 操作员
                    scanProWithout.getfInvCode(), // 物料编码
                    scanProcess.getScan(), // 物料条码
                    LocalDateTime.now(), // 时间
                    ScanProType.OK // 状态默认为正常
            );
            Helper.setDefaultAddValue(scanProAlready, fuserid);
            // 添加已扫描的工序
            scanProAlreadyMapper.saveScanProAlready(scanProAlready);
            // 记录操作步骤
            ScanProcessStep scanProcessStep = new ScanProcessStep(
                    scanProcess.getScan(), // 物料条码
                    scanProcess.getWpCode(), // 工序编号
                    scanProcess.getWpName(), // 工序名称
                    scanProcess.getUserCode(), // 用户编号
                    scanProcess.getUserName(), // 用户名称
                    LocalDateTime.now(), // 当前时间
                    StepType.INV, // 步骤类型
                    ProductType.PROCESSING, // 产品步骤
                    BusinessType.MOC
            );
            Helper.setDefaultAddValue(scanProcessStep, fuserid);
            // 新增操作步骤
            scanProcessStepMapper.addScanStep(scanProcessStep);
            show.setData(selectInv(scanProcess));
        }
        show.setScanMsg("物料：" + scanProcess.getInvCode() + "扫描成功！");
        return show;
    }

    @Override
    public ScanReport selectTotal(ScanProcess scanProcess) {
        // 判断条码/工序/扫描人 有一个有值 就进行查询操作
        Map<String, Object> sps = new HashMap<>(4);
        sps.put("fState", ParentEntity.FSTATE_DELETED);
        sps.put("dateTime", LocalDate.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd")));
        sps.put("businessType", BusinessType.MOC);
        List<ScanProcessStepVo> list = scanProcessStepMapper.selByNowDateScanProcessStep(sps);
        ScanReport info = new ScanReport();
        info.setNow(LocalDate.now());
        info.setOperator(scanProcess.getUserName());
        info.setScanPro(scanProcess.getWpCode());
        // 工序统计
        if (Helper.isNotEmpty(scanProcess.getWpCode())) {
            // 扫描台数（产品条码）
            BigDecimal proNum = new BigDecimal(list.stream().filter(data ->
                            Helper.isNotEmpty(data.getfScaPro()) &&
                                    data.getfProductType() == StepType.MOC &&
                                    scanProcess.getWpCode().equalsIgnoreCase(data.getfScaPro()) &&
                                    Helper.isNotEmpty(data.getfBarCode()))
                    .map(ScanProcessStepVo::getfBarCode).distinct().count());
            // 完成数（状态为正常报工）
            BigDecimal completeNum = new BigDecimal(list.stream().filter(data ->
                            Helper.isNotEmpty(data.getfScaPro()) &&
                                    scanProcess.getWpCode().equalsIgnoreCase(data.getfScaPro()) && Helper.isNotEmpty(data.getfBarCode())
                                    && data.getfProductType() == ProductType.FINISH)
                    .map(ScanProcessStepVo::getfBarCode).distinct().count());
            // 物料扫描数（状态位物料）
            BigDecimal invNum = BigDecimal.ZERO;
            // 获取所有过滤的步骤并且 根据物料条码分组
            Map<String, Integer> invMap = new HashMap<>();
            for (ScanProcessStepVo data : list) {
                boolean flag = Helper.isNotEmpty(data.getfScaPro()) &&
                        scanProcess.getWpCode().equalsIgnoreCase(data.getfScaPro()) &&
                        Helper.isNotEmpty(data.getfBarCode()) &&
                        (data.getfOperationDescription() == StepType.INV || data.getfOperationDescription() == StepType.DEL_INV);
                if (flag) {
                    String barCode = data.getfBarCode();
                    if (invMap.containsKey(barCode)) invMap.put(barCode, invMap.get(barCode) + 1);
                    else invMap.put(barCode, 1);
                }
            }
            for (String key : invMap.keySet()) {
                Integer count = invMap.get(key);
                // 过滤出来只有一条 则数量+1
                if (count == 1) {
                    invNum = invNum.add(BigDecimal.ONE);
                    continue;
                }
                // 若有多条 则判断当前扫描的数量是奇数还是偶数 应为是先有扫描再有的拆机
                // 所以当扫描的是奇数时则证明没有拆机否则是拆机
                if (count % 2 == 1) invNum = invNum.add(BigDecimal.ONE);
            }
            info.setProScan(new ScanCount(proNum, completeNum, invNum));
        }
        // 人员统计
        if (Helper.isNotEmpty(scanProcess.getUserCode())) {
            // 扫描台数（产品条码）
            BigDecimal proNum = new BigDecimal(list.stream().filter(data ->
                            Helper.isNotEmpty(data.getfOperatorCode()) &&
                                    data.getfProductType() == StepType.MOC &&
                                    scanProcess.getUserCode().equalsIgnoreCase(data.getfOperatorCode()) &&
                                    Helper.isNotEmpty(data.getfBarCode()))
                    .map(ScanProcessStepVo::getfBarCode).distinct().count());
            // 完成数（状态为正常报工）
            BigDecimal completeNum = new BigDecimal(list.stream().filter(data ->
                            Helper.isNotEmpty(data.getfOperatorCode()) &&
                                    scanProcess.getUserCode().equalsIgnoreCase(data.getfOperatorCode()) &&
                                    Helper.isNotEmpty(data.getfBarCode()) &&
                                    data.getfProductType() == ProductType.FINISH)
                    .map(ScanProcessStepVo::getfBarCode).distinct().count());
            // 物料扫描数（状态位物料）
            BigDecimal invNum = BigDecimal.ZERO;
            // 获取所有过滤的步骤并且 根据物料条码分组
            Map<String, Integer> invMap = new HashMap<>();
            for (ScanProcessStepVo data : list) {
                boolean flag =
                        Helper.isNotEmpty(data.getfOperatorCode()) &&
                                scanProcess.getUserCode().equalsIgnoreCase(data.getfOperatorCode()) &&
                                Helper.isNotEmpty(data.getfBarCode()) &&
                                (data.getfOperationDescription() == StepType.INV || data.getfOperationDescription() == StepType.DEL_INV);
                if (flag) {
                    String barCode = data.getfBarCode();
                    if (invMap.containsKey(barCode)) invMap.put(barCode, invMap.get(barCode) + 1);
                    else invMap.put(barCode, 1);
                }
            }
            for (String key : invMap.keySet()) {
                Integer count = invMap.get(key);
                // 过滤出来只有一条 则数量+1
                if (count == 1) {
                    invNum = invNum.add(BigDecimal.ONE);
                    continue;
                }
                // 若有多条 则判断当前扫描的数量是奇数还是偶数 应为是先有扫描再有的拆机
                // 所以当扫描的是奇数时则证明没有拆机否则是拆机
                if (count % 2 == 1) invNum = invNum.add(BigDecimal.ONE);
            }
            info.setOperateScan(new ScanCount(proNum, completeNum, invNum));
        }
        // 统计人员完工总数
        sps.clear();
        sps.put("fState", ParentEntity.FSTATE_DELETED);
        sps.put("businessType", BusinessType.MOC);
        sps.put("operatorCode", scanProcess.getUserCode());
        sps.put("proType", ProductType.FINISH);
        info.setTotal(BigDecimal.valueOf(scanProcessStepMapper.selectUserFinishTotal(sps)));
        return info;
    }

    @Override
    @Transactional
    public ScanProcessShow<Void> submit(ScanProcess scanProcess) throws Exception {
        ScanProcessShow<Void> show = new ScanProcessShow<>();
        if (Helper.isNotEmpty(scanProcess.getBarCode()) && Helper.isNotEmpty(scanProcess.getWpCode())) {
            Integer count = productProcessOlMapper.selectCount(new LambdaQueryWrapper<ProductProcessOl>()
                    .eq(ProductProcessOl::getfBarCode, scanProcess.getBarCode())
                    .eq(ProductProcessOl::getfWorkCode, scanProcess.getWpCode()));
            if (count > 0) {
                show.setScanCode(ScanType.ERROR);
                show.setScanMsg("该产品对应的工序已报工！不能重复报工！");
                return show;
            }
        }
        // 报工状态
        int code = scanProcess.getScan().equals("00") ? ProductType.FINISH : ProductType.ERROR;
        // 如果为正常报工 需要检查物料是否扫描完
        if (code == ProductType.FINISH) {
            Map<String, Object> map = new HashMap<>(2);
            map.put("fState", ParentEntity.FSTATE_DELETED);
            map.put("fBarCode", scanProcess.getBarCode());
            map.put("fWpCode", scanProcess.getWpCode());
            int without = scanProWithoutMapper.selByScanQueryCount(map);
            if (without > 0) { //还有未扫描的物料 不允许报工
                show.setScanCode(ScanType.ERROR);
                show.setScanMsg(scanProcess.getBarCode() + "：条码，在" + scanProcess.getWpCode() +
                        "工序上未完成所有的物料扫描，是否要强制进行报工？");
                return show;
            }
        }
        ScanProcessStep scanProcessStep = new ScanProcessStep(
                scanProcess.getBarCode(),
                scanProcess.getWpCode(),
                scanProcess.getWpName(),
                scanProcess.getUserCode(),
                scanProcess.getUserName(),
                LocalDateTime.now(),
                scanProcess.getScan().equals("00") ? StepType.OK : StepType.NO,
                code,
                BusinessType.MOC
        );
        String fuserid = loginUserRedisService.getUser().getFuserid();
        Helper.setDefaultAddValue(scanProcessStep, fuserid);
        // 保存当前报工的工序
        if (code == ProductType.FINISH) {
            ProductProcessOl ol = new ProductProcessOl();
            ol.setfBarCode(scanProcess.getBarCode());
            ol.setfWorkCode(scanProcess.getWpCode());
            Helper.setDefaultAddValue(ol, fuserid);
            productProcessOlMapper.insert(ol);
        }
        // 保存操作步骤
        scanProcessStepMapper.addScanStep(scanProcessStep);
        // 修改完工状态
        Map<String, Object> upt = new HashMap<>(4);
        upt.put("processing", code);
        upt.put("scan", scanProcess.getBarCode());
        upt.put("modify", fuserid);
        upt.put("time", LocalDateTime.now());
        productNumberMapper.updateProTypeByBarCode(upt);
        show.setScanMsg("报工成功！");
        return show;
    }

    @Override
    @Transactional
    public ScanProcessShow<Void> sureSubmit(ScanProcess scanProcess) throws Exception {
        ScanProcessShow<Void> show = new ScanProcessShow<>();
        // 报工状态
        int code = scanProcess.getScan().equals("00") ? ProductType.FINISH : ProductType.ERROR;
        ScanProcessStep scanProcessStep = new ScanProcessStep(
                scanProcess.getBarCode(),
                scanProcess.getWpCode(),
                scanProcess.getWpName(),
                scanProcess.getUserCode(),
                scanProcess.getUserName(),
                LocalDateTime.now(),
                scanProcess.getScan().equals("00") ? StepType.OK : StepType.NO,
                code,
                BusinessType.MOC
        );
        String fuserid = loginUserRedisService.getUser().getFuserid();
        Helper.setDefaultAddValue(scanProcessStep, fuserid);
        // 保存当前报工的工序
        if (code == ProductType.FINISH) {
            ProductProcessOl ol = new ProductProcessOl();
            ol.setfBarCode(scanProcess.getBarCode());
            ol.setfWorkCode(scanProcess.getWpCode());
            Helper.setDefaultAddValue(ol, fuserid);
            productProcessOlMapper.insert(ol);
        }
        // 保存操作步骤
        scanProcessStepMapper.addScanStep(scanProcessStep);
        // 修改完工状态
        Map<String, Object> upt = new HashMap<>(4);
        upt.put("processing", code);
        upt.put("scan", scanProcess.getBarCode());
        upt.put("modify", fuserid);
        upt.put("time", LocalDateTime.now());
        productNumberMapper.updateProTypeByBarCode(upt);
        show.setScanMsg("报工成功！");
        return show;
    }

    @Override
    @Transactional
    public ScanProcessShow<ScanInvVo> delInv(ScanProcess scanProcess) throws Exception {
        ScanProcessShow<ScanInvVo> show = new ScanProcessShow<>();
        Map<String, Object> map = new HashMap<>(4);
        // 状态不为删除
        map.put("fState", ParentEntity.FSTATE_DELETED);
        // 当前扫描的数据
        map.put("code", scanProcess.getBarCode());
        map.put("fInvCode", scanProcess.getInvCode());
        map.put("del", "del");
        ScanProWithoutVo scanProWithout = scanProWithoutMapper.selByInvCode(map);
        if (scanProWithout == null) { // 没有找到数据
            show.setScanCode(ScanType.ERROR);
            show.setScanMsg("暂无扫描的物料信息！");
            return show;
        } else {
            Helper.setEmptyWithNull(scanProWithout);
            String fuserid = loginUserRedisService.getUser().getFuserid();
            // 已扫描数减一
            BigDecimal qty = scanProWithout.getfAlreadyQty().subtract(BigDecimal.ONE);
            // 数量不能小于0
            scanProWithout.setfAlreadyQty(qty.compareTo(BigDecimal.ZERO) <= 0 ? BigDecimal.ZERO : qty);
            // 修改 原来的工序
            scanProWithout.setfLastModifyUserId(fuserid);
            scanProWithout.setfLastModifyTime(LocalDateTime.now());
            scanProWithoutMapper.updateQtyScanProWithout(scanProWithout);
            // 删除已扫描数据
            Map<String, Object> undo = new HashMap<>(5);
            undo.put("modify", fuserid);
            undo.put("time", LocalDateTime.now());
            undo.put("fId", scanProcess.getInvFid());
            undo.put("state", ParentEntity.FSTATE_DELETED);
            undo.put("proState", ScanProType.TEARDOWN);
            // 撤销已扫描数据
            scanProAlreadyMapper.undoScanProAlready(undo);
            show.setData(selectInv(scanProcess));
            ScanProcessStep scanProcessStep = new ScanProcessStep(
                    scanProcess.getScan(), // 条码号
                    scanProcess.getWpCode(),  // 工序编号
                    scanProcess.getWpName(), // 工序名称
                    scanProcess.getUserCode(), // 操作员编号
                    scanProcess.getUserName(), // 操作员名称
                    LocalDateTime.now(), // 当前时间
                    StepType.DEL_INV, // 操作步骤
                    ProductType.PROCESSING, // 产品进程
                    BusinessType.MOC
            );
            Helper.setDefaultAddValue(scanProcessStep, fuserid);
            scanProcessStepMapper.addScanStep(scanProcessStep);
        }
        show.setScanMsg("物料：" + scanProcess.getInvCode() + "扫描成功！");
        return show;
    }

    @Override
    public Map<String, Object> selectLastThree(ScanProcess scanProcess) {
        Map<String, Object> res = new HashMap<>(2);
        Map<String, Object> map = new HashMap<>(5);
        map.put("state", ParentEntity.FSTATE_DELETED);
        map.put("processing", ProductType.FINISH);
        map.put("sort", "FOperateTime");
        if (Helper.isNotEmpty(scanProcess.getWpCode())) map.put("wp", scanProcess.getWpCode());
        if (Helper.isNotEmpty(scanProcess.getUserCode())) map.put("op", scanProcess.getUserCode());
        List<ScanProcessStepVo> list = scanProcessStepMapper.selectLastThree(map);
        List<String> msgLis = new ArrayList<>(3);
        StringBuilder sb = new StringBuilder();
        DateTimeFormatter pattern = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
        sb.append("操作员：").append(scanProcess.getUserName()).append(" 在：")
                .append("'").append(scanProcess.getWpCode()).append("'").append("工序的")
                .append("最近").append(Math.min(list.size(), 3)).append("次的扫描记录如下");
        res.put("head", sb.toString());
        for (ScanProcessStepVo stepVo : list) {
            sb.delete(0, sb.length());
            sb.append(pattern.format(stepVo.getfOperateTime())).append(",").append("扫描了：")
                    .append(stepVo.getfBarCode()).append("条码");
            msgLis.add(sb.toString());
        }
        res.put("body", msgLis);
        return res;
    }

    /**
     * 设置扫描步骤
     */
    public ScanProcessStep setScanStep(Object obj, ScanProcess scanProcess, ScanProcessShow<?> show) {
        if (obj instanceof MocoRdersDisplayVo) {
            if (Helper.isNotEmpty(scanProcess.getBarCode())) {
                // 工单 返回的对象 不同
                show.setScanCode(ScanType.MOC);
                show.setScanMsg("工单扫描成功！");
                return new ScanProcessStep(
                        scanProcess.getBarCode(), scanProcess.getWpCode(), scanProcess.getWpName(),
                        scanProcess.getUserCode(), scanProcess.getUserName(), LocalDateTime.now(),
                        StepType.MOC, ProductType.PROCESSING, BusinessType.MOC
                );
            } else {
                show.setScanCode(ScanType.ERROR);
                show.setScanMsg("产品条码不能为空！");
            }
        } else if (obj instanceof WorkingProcedureVo) {
            if (Helper.isEmpty(scanProcess.getWpCode())) {
                show.setScanCode(ScanType.ERROR);
                show.setScanMsg("工序编号不能为空!");
            } else if (Helper.isEmpty(scanProcess.getWpName())) {
                show.setScanCode(ScanType.ERROR);
                show.setScanMsg("工序名称不能为空!");
            } else {
                show.setScanCode(ScanType.WP);
                show.setScanMsg("工序扫描成功！");
                return new ScanProcessStep(
                        scanProcess.getBarCode(), // 条码号
                        scanProcess.getWpCode(),  // 工序编号
                        scanProcess.getWpName(), // 工序名称
                        scanProcess.getUserCode(), // 操作员编号
                        scanProcess.getUserName(), // 操作员名称
                        LocalDateTime.now(), // 当前时间
                        StepType.WP, // 操作步骤
                        ProductType.PROCESSING, // 产品进程
                        BusinessType.MOC // 业务类型
                );
            }
        } else {
            if (Helper.isEmpty(scanProcess.getUserCode())) {
                show.setScanCode(ScanType.ERROR);
                show.setScanMsg("操作员编号不能为空!");
            } else if (Helper.isEmpty(scanProcess.getUserName())) {
                show.setScanCode(ScanType.ERROR);
                show.setScanMsg("操作员不能为空！");
            } else {
                show.setScanCode(ScanType.OP);
                show.setScanMsg("操作员扫描成功！");
                return new ScanProcessStep(
                        scanProcess.getBarCode(), scanProcess.getWpCode(), scanProcess.getWpName(),
                        scanProcess.getUserCode(), scanProcess.getUserName(), LocalDateTime.now(),
                        StepType.OP, ProductType.PROCESSING
                );
            }
        }
        return null;
    }
}
